# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import sys
import numpy as np
import matplotlib.pyplot as plt
from gm.api import *
import os
import talib
from 掘金3_分钟回测.专用的分析包 import *
from 掘金3_分钟回测.结论下定的包 import *

try:
    import statsmodels.tsa.stattools as ts
except:
    print('请安装statsmodels库')
    sys.exit(-1)

import matplotlib.pyplot as plt
import numpy as np
import matplotlib
from    掘金3_分钟回测.沪铜专用策略 import *

# 设置matplotlib正常显示中文和负号
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 用黑体显示中文
matplotlib.rcParams['axes.unicode_minus'] = False  # 正常显示负号
# 随机生成（10000,）服从正态分布的数据
# data = np.random.randn(10000)
"""
绘制直方图
data:必选参数，绘图数据
bins:直方图的长条形数目，可选项，默认为10
normed:是否将得到的直方图向量归一化，可选项，默认为0，代表不归一化，显示频数。normed=1，表示归一化，显示频率。
facecolor:长条形的颜色
edgecolor:长条形边框的颜色
alpha:透明度
"""
"""
plt.hist(data, bins=40, normed=0, facecolor="blue", edgecolor="black", alpha=0.7)
# 显示横轴标签
plt.xlabel("区间")
# 显示纵轴标签
plt.ylabel("频数/频率")
# 显示图标题
plt.title("频数/频率分布直方图")
plt.show()
"""

'''
本策略根据EG两步法(1.序列同阶单整2.OLS残差平稳)判断序列具有协整关系后(若无协整关系则全平仓位不进行操作)
通过计算两个价格序列回归残差的均值和标准差并用均值加减0.9倍标准差得到上下轨
在价差突破上轨的时候做空价差;在价差突破下轨的时候做多价差
若有仓位,在残差回归至上下轨内的时候平仓
回测数据为:SHFE.rb1801和SHFE.rb1805的1min数据
回测时间为:2017-09-25 08:00:00到2017-10-01 15:00:00
'''


# nowdays = ''


def init(context):
    # 按说这个是初始化
    context.nowdays = ''
    context.goods = ['SHFE.rb1801', 'SHFE.rb1805']
    # 订阅品种
    subscribe(symbols=context.goods, frequency='60s', count=8001, wait_group=True)

    subscribe(symbols=context.goods, frequency='3600s', count=8001, wait_group=True)
    # close = context.data(symbol=context.goods[0], frequency='60s', count=801, fields='close')['close'].values

    print("美好的一个策略开始了")


def on_bar(context, bars):
    # now = context.now
    # last_day = get_previous_trading_date('SHFE', now)
    # 获取过去800个60s的收盘价数据
    close = context.data(symbol=context.goods[0], frequency='60s', count=8001, fields='close')['close'].values
    # close_02 = context.data(symbol=context.goods[1], frequency='60s', count=801, fields='close')['close'].values
    # 展示两个价格序列的协整检验的结果

    # print('收盘价：', close[-1])
    # print('当前时间', str(context.now)[:10])
    # print(talib.MA(close, timeperiod=60))

    # 每天对数据进行分析
    if context.nowdays != str(context.now)[:10]:
        # 重新做一次数据分析
        context.nowdays = str(context.now)[:10]
        print('这是新的一天，先分析数据吧！')

        # 显示K线在MA两侧的分布情况(close_data=close, 周期=60)

        data = context.data(symbol=context.goods[0], frequency='60s', count=8001, fields='open,high,low,close')
        # print(data['close'])
        # 显示在指定周期的均线蜡烛线相交的情况(data=data,周期=60)
        # 显示震荡的周期是多少(data=data,周期=240)
        # 显示偏离MA的震荡周期内的最极值是多少折线图(data=data, 周期=90)
        # 显示偏离MA的震荡周期内的最极值的差值是多少(data=data, 周期=90)
        # 根据落在与均线差值的占比得出结论(当前价位=0, data=data, 周期=90, 默认的购入范围=0.8)
        # 显示从开始偏离MA线到最高和收盘的情况(data=data,周期=60,获取数=0)
        # 显示从开始偏离MA线到最高和收盘的情况

        M=均线上下分析()
        if M.是否购买(data=data)=='buy':
            order_target_volume(symbol=context.goods[0],
                                volume=1,
                                order_type=OrderType_Market,
                                position_side=PositionSide_Long
                                )
            print('买入1手','价格：',data['close'][-1])
        if M.是否购买(data=data)=='buy':
            order_target_volume(symbol=context.goods[0],
                                volume=1,
                                order_type=OrderType_Market,
                                position_side=PositionSide_Long
                                )
            print('买入1手','价格：',data['close'][-1])




# 计算残差的标准差上下轨

# # 获取rb1801的多空仓位
# position_01_long = context.account().position(symbol=context.goods[0], side=PositionSide_Long)
# # position_01_short = context.account().position(symbol=context.goods[0], side=PositionSide_Short)
# if not position_01_long and not position_01_short:
#     #  做空
#     if resid_new > up:
#         order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Short)
#         print(context.goods[0] + '以市价单开空仓1手')
#         order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Long)
#         print(context.goods[1] + '以市价单开多仓1手')
#     #  做多
#     if resid_new < down:
#         order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Long)
#         print(context.goods[0], '以市价单开多仓1手')
#         order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Short)
#         print(context.goods[1], '以市价单开空仓1手')
# #  平仓
# elif position_01_short:
#     if resid_new <= up:
#         order_close_all()
#         print('价格回归,平掉所有仓位')
#     # 突破下轨反向开仓
#     if resid_new < down:
#         order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Long)
#         print(context.goods[0], '以市价单开多仓1手')
#         order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Short)
#         print(context.goods[1], '以市价单开空仓1手')
# elif position_01_long:
#     if resid_new >= down:
#         order_close_all()
#         print('价格回归,平所有仓位')
#     #  开仓
#     if resid_new > up:
#         order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Short)
#         print(context.goods[0], '以市价单开空仓1手')
#         order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
#                             position_side=PositionSide_Long)
#         print(context.goods[1], '以市价单开多仓1手')
# 查看最终的回测结果
def on_backtest_finished(context, indicator):
    print(indicator)

if __name__ == '__main__':
    '''
    strategy_id策略ID,由系统生成
    filename文件名,请与本文件名保持一致
    mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST
    token绑定计算机的ID,可在系统设置-密钥管理中生成
    backtest_start_time回测开始时间
    backtest_end_time回测结束时间
    backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
    backtest_initial_cash回测初始资金
    backtest_commission_ratio回测佣金比例
    backtest_slippage_ratio回测滑点比例
    '''
    run(strategy_id='80fc12d8-ef58-11e9-89b5-b499baf0193a',
        filename=(os.path.basename(__file__)),
        mode=MODE_BACKTEST,
        token='90be3f863b23ab3c1ef68d1f9b8dc06e4bebb30d',
        backtest_start_time='2017-09-26 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=500000,
        # backtest_commission_ratio=0.0001,
        # backtest_slippage_ratio=0.0001
        )
